/*
 * Copyright (C), sensetime 2023
 * Author: dingjinfeng
 * Date: 2023/1/3 15:32
 * Description:
 */
package com.senseauto.autorecordlib;

import android.content.Context;
import android.os.Environment;
import android.util.Log;

import com.senseauto.autorecordlib.ffmpeg.FFmpegManager;
import com.senseauto.autorecordlib.mediacodec.IVideoEncoder;
import com.senseauto.autorecordlib.mediacodec.VideoEncoderAsyncImpl;
import com.senseauto.autorecordlib.strategy.RecordStrategy;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Locale;
import java.util.Timer;
import java.util.TimerTask;

public class RecordManager {
    // 回录的步骤：1、重复录制一段视频 2、结束时合成视频
    private static final String TAG = "RecordManager";
    private static final SimpleDateFormat mDateTimeFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss", Locale.US);
    private String RECORD_CACHE_DIR;
    private final int maxCacheCount = 2; // 最多存储2个临时视频
    private long currentVideoStartRecordTime = 0; // 当前录制视频开始时间
    private long currentVideoLength = 0; // 当前录制视频时长

    private static RecordManager instance;
    private RecordStrategy recordStrategy;
    private final IVideoEncoder videoEncoder;
    private final Timer recordTimer;
    private TimerTask recordTimerTask;
    private final List<String> videoPathList = new ArrayList<>(); // 录制的视频列表

    public static RecordManager getInstance(Context context) {
        if(instance == null) {
            synchronized (RecordManager.class) {
                if(instance == null) {
                    instance = new RecordManager(context);
                }
            }
        }
        return instance;
    }
    public void setRecordCacheDir(String path){
        RECORD_CACHE_DIR = path;
    }
    private RecordManager(Context context) {
        videoEncoder = new VideoEncoderAsyncImpl();
        recordTimer = new Timer();
        //RECORD_CACHE_DIR = Environment.getExternalStorageDirectory() + "/CarCacheVideo";
        RECORD_CACHE_DIR = new File(context.getExternalFilesDir(null), "CarCacheVideo").getAbsolutePath();
    }

    public void init(RecordStrategy recordStrategy) {
        Log.i(TAG, "init");
        this.recordStrategy = recordStrategy;
        deleteDir(RECORD_CACHE_DIR);
    }

    public void unInit() {
        deleteDir(RECORD_CACHE_DIR);
    }

    public void start() {
        Log.i(TAG, "start");
        videoPathList.clear();
        startRecord();
        if(recordStrategy.isContinuousRecord()) {
            recordTimerTask = new TimerTask() {
                @Override
                public void run() {
                    stopRecord();
                    startRecord();
                }
            };
            recordTimer.schedule(recordTimerTask, recordStrategy.getRecordMaxTime(), recordStrategy.getRecordMaxTime());
        }
    }

    /**
     * 目前仅支持YUV420P格式数据
     * @param data
     */
    public void encodeFrame(byte[] data) {
        videoEncoder.encode(data, System.nanoTime() / 1000L);
    }

    public void stop() {
        Log.i(TAG, "stop");
        recordTimerTask.cancel();
        stopRecord();

        if(videoPathList.size() == 1) {
            // 移动
            File file = new File(videoPathList.get(0));
            File finalFile = getCaptureFile(recordStrategy.getVideoDir());
            if(file == null || finalFile == null) return;
            file.renameTo(finalFile);
            Log.i(TAG, "save video file: " + finalFile.getAbsolutePath());
        } else {
            // 合并
            mergeVideo();
        }
    }

    private void startRecord() {
        Log.e(TAG, "startRecord");
        currentVideoStartRecordTime = System.currentTimeMillis();
        File file = getCaptureFile(RECORD_CACHE_DIR);
        videoPathList.add(file.getAbsolutePath());
        videoEncoder.init(file.getAbsolutePath(),
                recordStrategy.getVideoWidth(),
                recordStrategy.getVideoHeight(),
                recordStrategy.getFrameRate(),
                recordStrategy.getBitRate());
        videoEncoder.start();
    }

    private void stopRecord() {
        Log.i(TAG, "stopRecord");
        currentVideoLength = System.currentTimeMillis() - currentVideoStartRecordTime;
        videoEncoder.stop();
        videoEncoder.release();

        // 删除最老的视频
        if(videoPathList.size() > maxCacheCount) {
            File file = new File(videoPathList.get(0));
            if(file.exists()) {
                file.delete();
            }
            videoPathList.remove(0);
        }
    }

    private void mergeVideo() {
        Log.i(TAG, "mergeVideo");
        while(videoPathList.size() > maxCacheCount) {
            String path = videoPathList.remove(0);
            File file = new File(path);
            if(file.exists() && file.isFile()) {
                file.delete();
            }
        }
        File file = getCaptureFile(RECORD_CACHE_DIR);
        FFmpegManager.getInstance().concatVideo(videoPathList, file.getAbsolutePath());
        FFmpegManager.getInstance().clipVideo(currentVideoLength,
                currentVideoLength + recordStrategy.getRecordMaxTime(),
                file.getAbsolutePath(),
                getCaptureFile(recordStrategy.getVideoDir()).getAbsolutePath());
    }

    private File getCaptureFile(String dirName) {
        final File dir = new File(dirName);
        Log.i(TAG, "path=" + dir);
        dir.mkdirs();
        if (dir.canWrite()) {
            return new File(dir, getDateTimeString() + ".mp4");
        } else {
            Log.e(TAG, "getCaptureFile: dir can't write\n" + dir);
        }
        return null;
    }

    private boolean deleteDir(String path){
        File file = new File(path);
        if(!file.exists()){//判断是否待删除目录是否存在
            System.err.println("The dir are not exists!");
            return false;
        }

        String[] content = file.list();//取得当前目录下所有文件和文件夹
        for(String name : content){
            File temp = new File(path, name);
            if(temp.isDirectory()){//判断是否是目录
                deleteDir(temp.getAbsolutePath());//递归调用，删除目录里的内容
                temp.delete();//删除空目录
            }else{
                if(!temp.delete()){//直接删除文件
                    System.err.println("Failed to delete " + name);
                }
            }
        }
        return true;
    }

    private String getDateTimeString() {
        final GregorianCalendar now = new GregorianCalendar();
        return mDateTimeFormat.format(now.getTime());
    }
}
